package com.cn.appcore.base

import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.cn.appcore.config.AppException
import com.cn.appcore.config.ExceptionHandle
import com.cn.appcore.http.bean.BaseListResponse
import com.cn.appcore.http.bean.BaseResponse
import kotlinx.coroutines.*

/**
 * @author wxl
 * @date 2019/11/1
 * @desc BaseViewModel
 */
open class BaseViewModel : ViewModel(), LifecycleObserver {
    val loginSetMsg: MutableLiveData<Any> = MutableLiveData()
    val errorMsg: MutableLiveData<String> = MutableLiveData()
    val  againLoginMsg: MutableLiveData<String> = MutableLiveData()
    val netWorkMsg: MutableLiveData<String> = MutableLiveData()
    var getRewardErrorData = MutableLiveData<BaseResponse<Any>>()
    var getRewardListErrorData = MutableLiveData<BaseListResponse<Any>>()
    private fun launchOnUI(block: suspend CoroutineScope.() -> Unit) {
        MainScope().launch { block() }
        // viewModelScope.launch { block() }  /// ???
    }

    suspend fun <T> launchIO(block: suspend CoroutineScope.() -> T) {
        withContext(Dispatchers.IO) {
            block
        }
    }

    fun launch(tryBlock: suspend CoroutineScope.() -> Unit) {
        launchOnUI {
            tryCatch(tryBlock, {}, {}, true)
        }
    }
    fun launch(
        tryBlock: suspend CoroutineScope.() -> Unit,
        catchBlock: suspend CoroutineScope.(AppException) -> Unit) {
        launchOnUI {
            tryCatch(tryBlock,catchBlock, {}, true)
        }
    }

    fun launchOnUITryCatch(
        tryBlock: suspend CoroutineScope.() -> Unit,
        catchBlock: suspend CoroutineScope.(Throwable) -> Unit,
        finallyBlock: suspend CoroutineScope.() -> Unit,
        handleCancellationExceptionManually: Boolean
    ) {
        launchOnUI {
            tryCatch(tryBlock, catchBlock, finallyBlock, handleCancellationExceptionManually)
        }
    }

    fun launchOnUITryCatch(
        tryBlock: suspend CoroutineScope.() -> Unit,
        handleCancellationExceptionManually: Boolean = false
    ) {
        launchOnUI {
            tryCatch(tryBlock, {}, {}, handleCancellationExceptionManually)
        }
    }
    private suspend fun tryCatch(
        tryBlock: suspend CoroutineScope.() -> Unit,
        catchBlock: suspend CoroutineScope.(AppException) -> Unit,
        finallyBlock: suspend CoroutineScope.() -> Unit,
        handleCancellationExceptionManually: Boolean = false
    ) {
        coroutineScope {
            try {
                tryBlock()
            } catch (e: Exception) {

                if (e !is CancellationException || handleCancellationExceptionManually) {
                    catchBlock(ExceptionHandle.handleException(e))
                } else {
                    throw e
                }
            } finally {
                finallyBlock()
            }
        }
    }
}
